package server;

import java.nio.channels.ClosedChannelException;
import java.util.List;
import java.util.concurrent.*;

import server.schedulables.ScheduledRoundTransitions;

import common.PhaseEnum;
import common.Round;

public class Server {

	private ServerGameState state;
	private NetworkManager network;
	private Thread networkThread;
	
	private final int port;
	
	private ScheduledExecutorService scheduler;
	
	public Server( int port ) {
		this.port = port;
	}
	
	private void setup() {
		state = new ServerGameState();
		scheduler = Executors.newScheduledThreadPool( 2 );
		
		network = new NetworkManager( port, state, scheduler );
		networkThread = new Thread( network );
	}
	
	public void start() {
		setup();
		networkThread.start();
		
		scheduler.scheduleAtFixedRate( new ScheduledServerCheck( state, network ) , 1, 30, TimeUnit.SECONDS );
	}
	
	public void printServerStats() {
		network.printServerStats();
	}
	
	public void suggestShutdown() {
		networkThread.interrupt();
	}

	private class ScheduledServerCheck implements Runnable {
		
		private final ServerGameState state;
		private final NetworkManager network;

		public ScheduledServerCheck( ServerGameState state, NetworkManager network ) {
			this.state = state;
			this.network = network;
		}

		public void run() {
//			System.out.println("ScheduledServer check running...");

			if( network.getMediator() == null )
				return;
			
			List<Round> rounds = state.getAvailableRounds();
			int registerable = 0;
			
			for( Round r : rounds ) //Copy on Write array list so no concurrency issues
				if( r.getCurrentPhase() == PhaseEnum.REGISTRATION )
					++registerable;
			
			//If no round is found to be registerable, create a new one
			if( registerable == 0 || registerable == 1) {
				
				for( int i = 2; i > registerable; --i )
					createRound();

			}
		}
		
		private void createRound() {
			Round round = new Round();
			state.addRound( round );
			
			//Schedule the new round to have its phase transitioner
			// AND announce it to all connected clients so their RoundLists can be updated.
			ScheduledRoundTransitions transitioner = new ScheduledRoundTransitions( state, network.getMediator(), round );
			ScheduledFuture<?> future = network.getMediator().scheduleAtFixedRate( transitioner, 0, 10, TimeUnit.SECONDS);
			transitioner.setScheduledFuture( future );
			try {
				network.getMediator().sendToAllClients( round );
			} catch (ClosedChannelException e) {
				
			}
		}
		
	}
}
